/**
libICMath aims to be a powerful numerical calculation library, for more info see http://code.google.com/p/libicmath/
Copyright (C) IamMecone.com Development group

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

For more info check out the code available freely at http://code.google.com/p/libicmath/
Or check out our website at IamMeCone.com
 */

package com.ic.libICMath;

/**
 * A token to be used by the ICFunction class that contains every number, operator, function and anything else the ICFunction needs to parse and evaluate
 * 
 * @author Ean Lombardo
 * @since 1.0
 * @version 1.0
 */
public class ICMathToken implements Cloneable
{
	@Override
	/**
	 * Returns a hashcode for this token
	 * Autogenerated
	 * 
	 * @since 1.0
	 * @return This token's hashcode value
	 */
	public int hashCode()
	{
		final int prime = 31;
		int result = 1;
		result = prime * result + builtIn;
		result = prime * result + (done ? 1231 : 1237);
		result = prime * result + error;
		result = prime * result + ((function == null) ? 0 : function.hashCode());
		result = prime * result + ((magic == null) ? 0 : magic.hashCode());
		long temp;
		temp = Double.doubleToLongBits(number);
		result = prime * result + (int) (temp ^ (temp >>> 32));
		result = prime * result + operator;
		result = prime * result + params;
		result = prime * result + type;
		result = prime * result + (used ? 1231 : 1237);
		result = prime * result + ((variable == null) ? 0 : variable.hashCode());
		return result;
	}

	/**
	 * Checks by value to see if a token is equal to this token
	 * Autogenerated
	 * 
	 * @since 1.0
	 * @return (true,false) If this token is equal to the input by value
	 */
	@Override
	public boolean equals(Object obj)
	{
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		ICMathToken other = (ICMathToken) obj;
		if (builtIn != other.builtIn)
			return false;
		if (done != other.done)
			return false;
		if (error != other.error)
			return false;
		if (function == null)
		{
			if (other.function != null)
				return false;
		}
		else if (!function.equals(other.function))
			return false;
		if (magic == null)
		{
			if (other.magic != null)
				return false;
		}
		else if (!magic.equals(other.magic))
			return false;
		if (Double.doubleToLongBits(number) != Double.doubleToLongBits(other.number))
			return false;
		if (operator != other.operator)
			return false;
		if (params != other.params)
			return false;
		if (type != other.type)
			return false;
		if (used != other.used)
			return false;
		if (variable == null)
		{
			if (other.variable != null)
				return false;
		}
		else if (!variable.equals(other.variable))
			return false;
		return true;
	}

	private ICMathToken(double number, int type, int operator, String variable, String function, int error, boolean done, boolean used, String magic, int params, int builtIn) //used for quick cloning
	{
		super();
		this.number = number;
		this.type = type;
		this.operator = operator;
		this.variable = variable;
		this.function = function;
		this.error = error;
		this.done = done;
		this.used = used;
		this.magic = magic;
		this.params = params;
		this.builtIn = builtIn;
	}
	
	public ICMathToken() //used to allow simple construction seeing as the above constructor will make everything complaining about constructors even though its private
	{
	}
	
	/**
	 * Stores the number when the token is representing a number, otherwise null
	 * 
	 * @since 1.0
	 */
	public double number;
	
	/**
	 * Stores the type of the token, could be any of * or null
	 * 
	 * @since 1.0
	 */
	public int type;
	
	/**
	 * Stores the operator representation when the token is representing an operator, could be any of *
	 * 
	 * @since 1.0
	 */
	public int operator;
	
	/**
	 * Stores the name of the variable the token is representing if the token is representing a variable, otherwise null
	 * 
	 * @since 1.0
	 */
	public String variable;
	
	/**
	 * Stores the name of the user defined function if the token is representing a user defined function, otherwise null
	 * 
	 * @since 1.0
	 */
	public String function;

	/**
	 * Stores internal errors for figuring out if something went wrong
	 * 
	 * @since 1.0
	 */
	public int error;
	
	/**
	 * Set to true when evaluation is complete, used to know when to stop evaluation
	 * 
	 * @since 1.0
	 */
	boolean done;
	
	/**
	 * Used to know when the ICMathToken has been used from the output stack so that nothing has to be removed
	 * @since 1.0
	 */
	boolean used;
	
	/**
	 * Used for magic parsing, allows functions to use other functions or take fancy input that normally wouldn't work
	 * 
	 * @since 1.0
	 */
	public String magic;
	
	/**
	 * Stores the number of parameters the built in function was parsed as using, if this doesnt match up with hoe many it actually uses there will be an error
	 * 
	 * @since 1.0
	 */
	public int params;
	
	/**
	 * Used to store the representation of a built in function if the token is representing a built in function, otherwise null
	 * 
	 * @since 1.0
	 */
	int builtIn;
	
	/**
	 * Contains all of the different types an ICMathToken can represent
	 * 
	 *@since 1.0
	 */
	public static interface Types
	{
	public static final int NUMBER=1;
	public static final int OPERATOR=2;
	public static final int FUNCTION=3;
	public static final int VARIABLE=4;
	public static final int COMMA=5;
	public static final int MAGIC=6;
	public static final int BUILTIN_FUNCTION=7;
	}
	/**
	 * Contains all of the operators an ICMathToken can represent
	 * 
	 * @since 1.0
	 */
	public static interface Operators
	{
	public static final int PLUS=1;
	public static final int MINUS=2;
	public static final int MULTIPLY=3;
	public static final int DIVIDE=4;
	public static final int POWER=5;
	public static final int MODULUS=6;
	public static final int FACTORIAL=7;
	public static final int EQUALS=8;
	public static final int GREATER_THAN=9;
	public static final int LESS_THAN=10;
	public static final int LESS_THAN_EQUAL=11;
	public static final int GREATER_THAN_EQUAL=12;
	public static final int NOT_EQUAL=13;
	public static final int ASSIGN=14;
	public static final int PARENTHESES_OPEN=15;
	public static final int PARENTHESES_CLOSE=16;
	}
	
	/**
	 * An array of all of the operators supported by the tokens, note arrays start at 0 and type constants start at one so the string is STRINGS[type-1]
	 */
	public static final String STRINGS[]={"+","-","*","/","^","(",")","%",":=","!","=",">","<","≤","≥","≠"};
	
	
	/**
	 * Gets the precedence of the operator
	 * 
	 * @since 1.0
	 * @return The precedence of the operator if the token represents an operator, otherwise returns -1
	 */
	public int prec()
	{
		switch (operator)
		{
		case Operators.EQUALS:
		case Operators.GREATER_THAN:
		case Operators.LESS_THAN:
		case Operators.LESS_THAN_EQUAL:
		case Operators.GREATER_THAN_EQUAL:
		case Operators.NOT_EQUAL:
			return 4;
		case Operators.PLUS:
		case Operators.MINUS:
			return 3;
		case Operators.MULTIPLY:
		case Operators.DIVIDE:
		case Operators.MODULUS:
			return 2;
		case Operators.POWER:
			return 1;

		}
		return -1;
	}
	
	public String toString()
	{
		if (done)
		{
			return "EOS";
		}
		else if (error != 0)
		{
			return "error number:" + String.valueOf(error);
		}
		else if (type == Types.NUMBER)
		{
			return String.valueOf(number);
		}
		else if (type == Types.OPERATOR)
		{
			return STRINGS[operator-1];
		}
		else if (type == Types.FUNCTION)
		{
			return function;
		}
		else if (type == Types.VARIABLE)
		{
			return variable;
		}
		else if (type == Types.COMMA)
		{
			return ",";
		}
		else if (type == Types.MAGIC)
		{
			return "|"+magic+"|";
		}
		else if (type==Types.BUILTIN_FUNCTION)
		{
			return ICMath.builtInFunctions[builtIn-1];
		}
		else
		{
			return "error";
		}

	}
	
	/**
	 * Gets a clone of the token
	 * 
	 * @since 1.0
	 * @return A token will all of the exact same field values, a clone of this token
	 */
	@Override
	public ICMathToken clone()
	{
		return new ICMathToken(number,type,operator,variable==null?null:new String(variable), function==null?null:new String(function),error,done,used, magic==null?null:new String(magic),params,builtIn); //does a quick clone, yay for ternary operators
	}

}